{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_decision_making:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ".. meta::\n",
    "   :description: Multi-criteria Decision Making addresses the selection of a solution set with multiple conflicting objectives."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ".. meta::\n",
    "   :keywords: Multi-criteria Decision Making, MCDM, Multi-objective Optimization, Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Multi-Criteria Decision Making (MCDM)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The focus of pymoo is on optimization methods itself. However, some basic multi-criteria decision making methods are available:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_compromise:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Compromise Programming"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use any scalarization method and use it for post-processing. Let us assume our algorithm has converged to the Pareto-front:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pymoo.problems import get_problem\n",
    "\n",
    "F = get_problem(\"zdt1\").pareto_front() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then, we initialize weights and our decomposition function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from pymoo.decomposition.asf import ASF\n",
    "\n",
    "weights = np.array([0.5, 0.5])\n",
    "decomp = ASF()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We apply the decomposition and retrieve the best value (here minimum):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "I = decomp(F, weights).argmin()\n",
    "print(\"Best regarding decomposition: Point %s - %s\" % (I, F[I]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Visualize it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pymoo.visualization.scatter import Scatter\n",
    "\n",
    "plot = Scatter()\n",
    "plot.add(F, color=\"blue\", alpha=0.2, s=10)\n",
    "plot.add(F[I], color=\"red\", s=30)\n",
    "plot.do()\n",
    "plot.apply(lambda ax: ax.arrow(0, 0, 0.5, 0.5, color='black', \n",
    "                               head_width=0.01, head_length=0.01, alpha=0.4))\n",
    "plot.show()"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_pseudo_weights:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pseudo-Weights"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A simple way to chose a solution out of a solution set in the context of multi-objective optimization is the pseudo-weight vector approach proposed in <cite data-cite=\"multi_objective_book\"></cite>. Respectively, the pseudo weight $w_i$ for the i-ith objective function can be calculated by:\n",
    "\n",
    "\\begin{equation}\n",
    "w_i = \\frac{(f_i^{max} - f_i {(x)}) \\, /\\,  (f_i^{max} - f_i^{min})}{\\sum_{m=1}^M (f_m^{max} - f_m (x)) \\, /\\,  (f_m^{max} - f_m^{min})}  \n",
    "\\end{equation}\n",
    "\n",
    "This equation calculates the normalized distance to the worst solution regarding each objective $i$. Please note that for non-convex Pareto fronts the pseudo weight does not correspond to the result of an optimization using the weighted sum. However, for convex Pareto-fronts the pseudo weights are an indicator of the location in the objective space."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pymoo.mcdm.pseudo_weights import PseudoWeights\n",
    "from pymoo.util.ref_dirs import get_reference_directions\n",
    "from pymoo.visualization.petal import Petal\n",
    "\n",
    "ref_dirs = get_reference_directions(\"das-dennis\", 4, n_partitions=12)\n",
    "F = get_problem(\"dtlz1\").pareto_front(ref_dirs)\n",
    "\n",
    "weights = np.array([0.25, 0.25, 0.25, 0.25])\n",
    "a, pseudo_weights = PseudoWeights(weights).do(F, return_pseudo_weights=True)\n",
    "\n",
    "weights = np.array([0.4, 0.20, 0.15, 0.25])\n",
    "b, pseudo_weights = PseudoWeights(weights).do(F, return_pseudo_weights=True)\n",
    "\n",
    "plot = Petal(bounds=(0, 0.5), reverse=True)\n",
    "plot.add(F[[a, b]])\n",
    "plot.show()"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_high_tradeoff:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### High Trade-off Points"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Furthermore, high trade-off points are usually of interest. We have implemented the trade-off metric proposed in <cite data-cite=\"high-tradeoff\"></cite>. An example for 2 and 3 dimensional solution is given below:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "import numpy as np\n",
    "from pymoo.visualization.scatter import Scatter\n",
    "from pymoo.mcdm.high_tradeoff import HighTradeoffPoints\n",
    "\n",
    "pf = np.loadtxt(\"knee-2d.out\")\n",
    "dm = HighTradeoffPoints()\n",
    "\n",
    "I = dm(pf)\n",
    "\n",
    "plot = Scatter()\n",
    "plot.add(pf, alpha=0.2)\n",
    "plot.add(pf[I], color=\"red\", s=100)\n",
    "plot.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pf = np.loadtxt(\"knee-3d.out\")\n",
    "\n",
    "I = dm(pf)\n",
    "\n",
    "plot = Scatter(angle=(10, 140))\n",
    "plot.add(pf, alpha=0.2)\n",
    "plot.add(pf[I], color=\"red\", s=100)\n",
    "plot.show()"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
